﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace Webcam.Image.Filters
{
    /// <summary>
    /// The sobel edge finding algorithm
    /// </summary>
    public class Sobel : ImageAction
    {
        public Sobel(RGBImage img)
            : base(img)
        {
        }

        /// <summary>
        /// The lower limit of grayness
        /// </summary>
        public byte GraynessLimit = 35;

        /// <summary>
        /// Process the img using the sobel algorithm
        /// </summary>
        public override void Process()
        {
            this.output = new RGBImage(src.Width, src.Height, RGB.Black);
            // the 3x3 GX sobel mask.
            // Ref. http://www.cee.hw.ac.uk/hipr/html/sobel.html
            //      http://www.pages.drexel.edu/~weg22/edge.html
            int[][] GX = new int[3][];
            for (int i = 0; i < 3; i++)
                GX[i] = new int[3];
            GX[0][0] = -1; GX[0][1] = 0; GX[0][2] = 1;
            GX[1][0] = -2; GX[1][1] = 0; GX[1][2] = 2;
            GX[2][0] = -1; GX[2][1] = 0; GX[2][2] = 1;




            // 3x3 GY sobel mask
            // Ref. http://www.cee.hw.ac.uk/hipr/html/sobel.html
            //      http://www.pages.drexel.edu/~weg22/edge.html
            int[][] GY = new int[3][];
            for (int i = 0; i < 3; i++)
                GY[i] = new int[3];
            GY[0][0] = 1; GY[0][1] = 2; GY[0][2] = 1;
            GY[1][0] = 0; GY[1][1] = 0; GY[1][2] = 0;
            GY[2][0] = -1; GY[2][1] = -2; GY[2][2] = -1;


            for (int Y = 0; Y < src.Height; Y++)
            {
                for (int X = 0; X < src.Width; X++)
                {
                    int sumX = 0;
                    int sumY = 0;
                    int SUM = 0;

                    // image boundaries
                    if (Y == 0 || Y == src.Height - 1)
                        SUM = 0;
                    else if (X == 0 || X == src.Width - 1)
                        SUM = 0;
                    else
                    {
                        /* ---- X GRADIENT APPROXIMATION -- */
                        for (int I = -1; I <= 1; I++)
                        {
                            for (int J = -1; J <= 1; J++)
                            {
                                sumX += (int)src[X + I, Y + J].GrayScale * GX[I + 1][J + 1];
                            }
                        }

                        /*-------Y GRADIENT APPROXIMATION-------*/
                        for (int I = -1; I <= 1; I++)
                        {
                            for (int J = -1; J <= 1; J++)
                            {
                                sumY += (int)src[X + I, Y + J].GrayScale * GY[I + 1][J + 1];
                            }
                        }

                        /*---GRADIENT MAGNITUDE APPROXIMATION (Myler p.218)----*/
                        SUM = Math.Abs(sumX) + Math.Abs(sumY);

                    }
                    if (SUM > 255)
                        SUM = 255;
                    if (SUM < 0)
                        SUM = 0;

                    int grayness = SUM;

                    // remove the small differences
                    if (grayness < GraynessLimit)
                        continue;

                    RGB px = this.output[X, Y];
                    px.GrayScale = (byte)grayness;
                    this.output[X, Y] = px;
                }
            }
        }

        
    }
}
